package com.java.inventory.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.java.inventory.common.enums.ExceptionEnum;
import com.java.inventory.common.exception.BizException;
import com.java.inventory.dbparam.InventoryLockParam;
import com.java.inventory.dto.LockInventoryReq;
import com.java.inventory.entity.Inventory;
import com.java.inventory.mapper.InventoryMapper;
import com.java.inventory.service.IInventoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.RedissonNode;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 库存表 服务实现类
 * </p>
 *
 * @author jobob
 * @since 2022-11-16
 */
@Service
public class InventoryServiceImpl extends ServiceImpl<InventoryMapper, Inventory> implements IInventoryService {

    @Resource
    private RedissonClient redissonClient;


    public Map<String, Inventory> queryInv(List<LockInventoryReq.LockInventoryParam> lockInventoryParamList){

        //查缓存
        Map<String, Inventory> inventoryMap = new HashMap<>();
        for (LockInventoryReq.LockInventoryParam lockInventoryParam : lockInventoryParamList) {
            String key = lockInventoryParam.getProductId() + "_" + lockInventoryParam.getWarehosueCode();
            inventoryMap.put(key,null);
        }
        Set<String> keySet = inventoryMap.keySet();

        String[] keyArr = keySet.toArray(new String[keySet.size()]);
        inventoryMap = redissonClient.getBuckets().get(keyArr);

        if (inventoryMap.size() == lockInventoryParamList.size()){
            return inventoryMap;
        }
        Set<String> warehosueCodeList = new HashSet<>();
        Set<Long> productIdList = new HashSet<>();
        for (LockInventoryReq.LockInventoryParam lockInventoryParam : lockInventoryParamList) {
            String key = lockInventoryParam.getProductId() + "_" + lockInventoryParam.getWarehosueCode();
            if (!inventoryMap.containsKey(key)){
                warehosueCodeList.add(lockInventoryParam.getWarehosueCode());
                productIdList.add(lockInventoryParam.getProductId());
            }
        }

        //查询库存
        LambdaQueryWrapper<Inventory> wrapper = Wrappers.lambdaQuery();
        wrapper.in(Inventory::getWarehosueCode, warehosueCodeList);
        wrapper.in(Inventory::getProductId, productIdList);
        List<Inventory> inventoryList = this.baseMapper.selectList(wrapper);
        if (!CollectionUtils.isEmpty(inventoryList)){
            Map<String, Inventory> dbInventory = new HashMap<>();
            for (Inventory inventory : inventoryList) {
                dbInventory.put(inventory.getProductId() + "_" + inventory.getWarehosueCode(), inventory);
            }
            redissonClient.getBuckets().set(dbInventory);
            inventoryMap.putAll(dbInventory);
        }
        return inventoryMap;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void lockInventory(LockInventoryReq lockInventoryReq) {

        List<LockInventoryReq.LockInventoryParam> lockInventoryParamList = lockInventoryReq.getLockInventoryParamList();

        Map<String, Inventory> inventoryMap = queryInv(lockInventoryParamList);

        //校验库存
        Map<Long,Long> lockMap = new HashMap<>();
        for (LockInventoryReq.LockInventoryParam lockInventoryParam : lockInventoryParamList) {
            String key = lockInventoryParam.getProductId() + "_" + lockInventoryParam.getWarehosueCode();
            Inventory inventory = inventoryMap.get(key);
            if (inventory == null) {
                throw new BizException(ExceptionEnum.INVENTORY_NOT_ENOUGH);
            }
            Long avaNum = inventory.getAvaNum();
            if (avaNum < lockInventoryParam.getLockNum()){
                throw new BizException(ExceptionEnum.INVENTORY_NOT_ENOUGH);
            }
            lockMap.put(inventory.getId(),lockInventoryParam.getLockNum());
        }
        //执行更新逻辑
        List<InventoryLockParam> lockParamList = new ArrayList<>();
        for (Map.Entry<Long, Long> entry : lockMap.entrySet()) {
            InventoryLockParam lockParam = new InventoryLockParam();
            lockParam.setId(entry.getKey());
            lockParam.setLockNum(entry.getValue());
            lockParamList.add(lockParam);
        }
        //排序 防止死锁
        lockParamList.sort((o1, o2) -> (int) (o1.getId() - o2.getId()));
        //循环更新
        for (InventoryLockParam lockParam : lockParamList) {
            int num = this.getBaseMapper().lockInventory(lockParam.getId(), lockParam.getLockNum());
            if (num < 1){
                throw new BizException(ExceptionEnum.INVENTORY_CHANGE_FAIL);
            }
        }
    }
}
